<template>
  <view class="cropper">
    <!-- #ifdef MP -->
    <view class="action flex justify-between" :style="{top:'calc(88rpx + '+systemInfo.statusBarHeight+'rpx)'}">
      <!-- #endif -->
      <!-- #ifdef H5 -->
      <view class="action flex justify-between" :style="{top:'88rpx'}">
        <!-- #endif -->
        <view @click="close" style="color:#fff;">
          取消
        </view>
        <view @click="draw" style="color: #ea4757">
          完成
        </view>
      </view>
      <movable-area :style="{ height: movableAreaHeight +'px',width:movableAreaWidth+'px'}" class="movable-area" scale-area v-if="showMoveView"
                    @click="showDownContainer=false">
        <movable-view id="m-v" class="m-view" direction="all"
                      scale-min="1"
                      :scale="false"
                      scale-max="5"
                      :x="xOffset"
                      :y="yOffset"
                      :out-of-bounds="false"
                      @change="move"
                      @scale="handleScale"
                      :style="{width:mViewWidth+'px',height:mViewHeight+'px'}">
        </movable-view>
      </movable-area>

      <view v-if="shape == 'circle'" class="hole-bg" id="hole">
        <view class="hole" :class="{'circle':shape=='circle'}"></view>
      </view>
      <view v-else class="hole-bg" id="hole">
        <view class="hole" :style="{width: holeWidth+'px',height:holeHeight+'px' }" :class="{'circle':shape=='circle'}"></view>
      </view>
      <canvas canvas-id="canvas" style="width:100%;height:100%"></canvas>
      <image v-if="showPic" :style="{top:imgY+'px',left:imgX+'px',height: imgH + 'px',width:imgW +'px'}" class="img"
             :src="imgSrc" :mode="shape == 'circle' ? 'widthFix' : 'aspectFit'"></image>
      <view></view>
      <!--		<view class="btn-group flex justify-between">-->
      <!--&lt;!&ndash;			<button @click="draw(true)"  class="select-btn flex justify-center align-center">&ndash;&gt;-->
      <!--&lt;!&ndash;				&lt;!&ndash; #ifndef H5 &ndash;&gt;&ndash;&gt;-->
      <!--&lt;!&ndash;				保存图像&ndash;&gt;-->
      <!--&lt;!&ndash;				&lt;!&ndash; #endif &ndash;&gt;&ndash;&gt;-->
      <!--&lt;!&ndash;				&lt;!&ndash; #ifdef H5 &ndash;&gt;&ndash;&gt;-->
      <!--&lt;!&ndash;				生成图像&ndash;&gt;-->
      <!--&lt;!&ndash;				&lt;!&ndash; #endif &ndash;&gt;&ndash;&gt;-->
      <!--&lt;!&ndash;				</button>&ndash;&gt;-->
      <!--&lt;!&ndash;			<button @click="selectPic" class="select-btn flex justify-center align-center">选择图片</button>&ndash;&gt;-->
      <!--		</view>-->
      <!-- #ifdef H5 -->
      <view class="download-img-container" :class="[shape=='circle'?'circle':'square']" v-if="showDownContainer">
        <image :src="clipFilePath"></image>
        <view class="text">长按图片保存</view>
      </view>
      <!-- #endif -->
      <!--	</view>-->
    </view>

</template>

<script>
/**
 * 本来想用movable-view变换之后的比例来计算图片宽高的，但缩放后的宽高(x,y)无法定位准确，用了dom的查询方法，后续有空更新wxs的位移方法
 */
export default {
  data() {
    return {
      movableAreaHeight: 0,
      movableAreaWidth:0,
      holeWidth:0,
      scale: 1,// 缩放比例，本来想用它计算图片宽高，但缩放后的宽高(x,y)无法定位准确
      initWidth: 0,// 初始宽度
      holeHeight: 0,// 初始宽度
      initHeight: 0,// 初始高度
      mViewInitX: 0,// 移动层初始偏移量
      mViewInitY: 0,// 移动层初始偏移量
      imgInitX: 0,// 图片初始偏移量
      imgInitY: 0,// 图片初始偏移量

      mViewWidth: 0,// 移动层宽度
      mViewHeight: 0,// 移动层高度
      mViewX: 0,// 移动层左上x坐标
      mViewY: 0,// 移动层左上y坐标
      xOffset: 0,// 移动层初始x偏移量
      yOffset: 0,// 移动层初始y偏移量
      showMoveView: false,// 是否开启移动层(待初始数据设置好才开启)
      showPic: true,// 是否显示图片(待移动层数据设置好才显示)
      imgX: 0,// 图片左上x坐标
      imgY: 0,// 图片左上y坐标
      imgW: 0,// 图片宽度
      imgH: 0,// 图片高度
      imgHeight: 0,// 图片高度
      avatarCenterX: 0,// 选择框中心x坐标
      avatarCenterY: 0,// 选择框中心y坐标
      imgSrc: '',// 图片地址
      holeSize: 0,// 选择框半径
      systemInfo: {statusBarHeight: 0},// 系统信息
      clipFilePath: '',
      showDownContainer: false
    }
  },
  props: {
    /**
     * 裁切形状 circle,square
     */
    shape: {
      type: String,
      default: 'circle'
    },
    /**
     * 默认显示图片
     */
    imgUrl: {
      type: String,
      default: ''
    },
    /**
     * 是否使用上传
     */
    useUpload: {
      type: Boolean,
      default: false
    },
    /**
     * 上传的请求头
     */
    header: {
      type: Object,
      default() {
        return {}
      }
    },
    /**
     * 上传文件的键名
     */
    name: {
      type: String,
      default: 'file'
    },
    /**
     * 自定义上传内容
     */
    formData: {
      type: Object,
      default() {
        return {}
      }
    }
  },
  created() {
    if (this.imgUrl != '') {
      this.imgSrc = this.imgUrl
    }
  },
  mounted() {
    let _this = this
    let query = uni.createSelectorQuery().in(this)
    let systemInfo = uni.getSystemInfoSync()
    if(this.shape == 'square'){
      this.holeWidth = systemInfo.windowWidth
      this.holeHeight = Math.round(systemInfo.windowWidth * (9 / 16))
    }
    // console.log('系统信息', systemInfo)
    this.systemInfo = systemInfo
    query.select('#hole').boundingClientRect()
    query.exec(function (res) {
      // console.log('hole的参数', res)
      let holeRect = res[0], holeSize = _this.shape == 'square' ?  systemInfo.windowWidth : systemInfo.windowWidth / (750 / 560)
      // console.log(holeSize)
      _this.avatarCenterX = holeRect.width / 2 + holeRect.left

      //#ifndef H5
      _this.avatarCenterY = holeRect.height / 2 + holeRect.top
      //#endif
      //#ifdef H5
      //H5下使用默认导航栏，获取的top会减去导航栏高度,所以要把systemInfo.windowTop加上
      _this.avatarCenterY = holeRect.height / 2 + holeRect.top + systemInfo.windowTop
      //#endif
      _this.holeSize = _this.shape == 'square' ?  systemInfo.windowWidth : systemInfo.windowWidth / (750 / 560)
      // console.log(_this.holeSize)

      if (_this.imgSrc != '') {
        _this.$nextTick(() => {
          _this.getImageInfo(holeSize, systemInfo)
        })
      }
      setTimeout(() => {
        _this.selectPic()
      }, 500)

    })
  },
  methods: {
    close() {
      this.$emit('close', false)
    },
    /**
     * 选择图片
     */
    selectPic() {
      let _this = this
      uni.chooseImage({
        count: 1,
        sizeType: ['compressed'],
        success: (res) => {
          // console.log('获取图片', res)
          _this.originSrc = res.tempFiles[0]
          _this.imgSrc = res.tempFilePaths[0]
          _this.$nextTick(() => {
            _this.getImageInfo(_this.holeSize, _this.systemInfo)
          })
        },
        fail() {
          // _this.$Router.back()
        },
        complete() {
          // console.log('选择完')
        }
      });
    },
    /**
     * 获取图片信息
     * @param {Object} holeSize
     * @param {Object} systemInfo
     */
    getImageInfo(holeSize, systemInfo) {
      let _this = this
      uni.getImageInfo({
        src: _this.imgSrc,
        success(res) {
          // console.log('图片信息', res)

          //#ifndef H5
          let systemHeight = systemInfo.windowHeight,
              systemWidth = systemInfo.windowWidth
          //#endif
          //#ifdef H5
          //H5下使用默认导航栏，获取的systemInfo.windowHeight会减去导航栏高度,所以要把systemInfo.windowTop加上
          let systemHeight = systemInfo.windowHeight + systemInfo.windowTop,
              systemWidth = systemInfo.windowWidth
          //#endif

          if (res.height <= res.width) {
            // var initHeight = _this.shape == 'square' ? _this.holeHeight :  holeSize,
            var initHeight =  holeSize,
                initWidth = _this.shape == 'square' ? systemInfo.windowWidth : holeSize * res.width / res.height,
                imgInitX = systemInfo.windowWidth / 2 - holeSize * res.width / res.height / 2,
                imgInitY = systemHeight / 2 - holeSize / 2,
                mViewInitX = systemInfo.windowWidth * 5 / 2 - holeSize * res.width / res.height / 2,
                mViewInitY = systemHeight * 5 / 2 - holeSize / 2

          } else {
            // var initWidth = holeSize,
            var initWidth = _this.shape == 'square' ? systemInfo.windowWidth : holeSize,
                initHeight = holeSize * res.height / res.width,
                imgInitX = systemInfo.windowWidth / 2 - holeSize / 2,
                imgInitY = systemHeight / 2 - holeSize * res.height / res.width / 2,
                mViewInitX = systemInfo.windowWidth * 5 / 2 - holeSize / 2,
                mViewInitY = systemHeight * 5 / 2 - holeSize * res.height / res.width / 2

          }
          imgInitY = _this.shape == 'square' ? 0 : imgInitY
          imgInitX = _this.shape == 'square' ? 0 : imgInitX
          _this.movableAreaHeight = _this.shape == 'square' ? initHeight * 2 - 0.75 * holeSize    : initHeight * 2 - holeSize
          _this.movableAreaWidth = _this.shape == 'square' ? systemInfo.windowWidth: initWidth * 2 - holeSize

          _this.initWidth = initWidth
          _this.initHeight = initHeight

          _this.mViewInitX = mViewInitX
          _this.mViewInitY = mViewInitY
          _this.imgInitX = imgInitX
          _this.imgInitY = imgInitY

          _this.mViewWidth = initWidth
          _this.mViewHeight = initHeight
          _this.imgHeight = _this.mViewHeight
          _this.imgW = initWidth
          _this.imgH =  initHeight
          _this.xOffset = mViewInitX //移动层是相对移动框
          _this.yOffset = mViewInitY
          _this.imgX = imgInitX //图片的是相对cropper
          _this.imgY = imgInitY
          _this.$nextTick(function () {
            _this.showMoveView = true
            _this.showPic = true
          })
        }
      })
    },
    /**
     * 保存图片
     * @param {Object} clipFilePath
     */
    savePic(clipFilePath) {
      //#ifdef MP-WEIXIN
      uni.saveImageToPhotosAlbum({
        filePath: clipFilePath,
        success(res) {
          // console.log('保存成功', res)
        }
      })
      //#endif

      //#ifdef H5
      this.showDownContainer = true
      //#endif
    },
    /**
     * 生成圆形头像
     */
    draw(savePic = false) {
      if (this.imgSrc == '') {
        uni.showToast({title: '未选择图片', icon: 'none'});
        return false
      }
      uni.showLoading({
        title: '图像生成中',
      })
      let {avatarCenterX, avatarCenterY, imgX, imgY, imgW, imgH, holeSize, scale} = this,

          _this = this

      var context = uni.createCanvasContext('canvas', this)
      context.setFillStyle('#ffffff')
      context.save()
      if (_this.shape == 'circle') {
        context.beginPath()
        context.arc(avatarCenterX, avatarCenterY, holeSize / 2, 0, 2 * Math.PI)
        context.clip()
      }
      context.drawImage(this.imgSrc, imgX, imgY, imgW, imgH)
      // console.log(holeSize)
      // console.log(this.imgSrc,imgX, imgY, imgW, imgH)
      context.restore()
      // console.log(imgW, imgH)
      // console.log( _this.holeWidth, _this.holeHeight)
      // console.log(_this.systemInfo.pixelRatio)
      // console.log( _this.holeWidth * _this.systemInfo.pixelRatio,_this.holeHeight * _this.systemInfo.pixelRatio)
      context.draw(true, () => {
        setTimeout(() => {
          uni.canvasToTempFilePath({
            canvasId: 'canvas',
            fileType: 'png',
            quality: 1,
            x: _this.shape == 'circle' ? avatarCenterX - holeSize/2  : imgH,
            y: _this.shape == 'circle' ? avatarCenterY - holeSize/2 : avatarCenterY - holeSize/4,
            // x: avatarCenterX - holeSize / 2  ,
            // y: avatarCenterY - holeSize/4,
            width:   _this.shape == 'circle' ? holeSize : _this.holeWidth,
            height:  _this.shape == 'circle' ? holeSize : _this.holeHeight,
            destWidth:  _this.shape == 'circle' ? holeSize * _this.systemInfo.pixelRatio : _this.holeWidth * _this.systemInfo.pixelRatio  ,
            destHeight: _this.shape == 'circle' ? holeSize * _this.systemInfo.pixelRatio : _this.holeHeight * _this.systemInfo.pixelRatio,
            success(res) {
              // console.log('canvasToTempFilePath： ' )
              // console.log(res)

              context.setFillStyle('#ffffff')
              context.fill()
              context.draw()
              _this.$emit('drawSuccess', res)
              _this.clipFilePath = res.tempFilePath
              if (savePic === true) {
                _this.$nextTick(() => {
                  _this.savePic(res.tempFilePath)
                })
              }
              // console.log('生成图片结果',res)
              if (!_this.useUpload) {
                // uni.showToast({
                // 	title:'图像裁切成功'
                // })
              }

              if (_this.useUpload) {
                uni.showLoading({
                  title: '图片上传中'
                })
                let header = {
                  //#ifdef MP
                  "Content-Type": "multipart/form-data",
                  //#endif
                }
                header = Object.assign(header, _this.header)
                uni.uploadFile({
                  url: _this.url,
                  filePath: res.tempFilePath,
                  name: _this.name,
                  header: header,
                  formData: _this.formData,
                  success(res) {
                    _this.$emit('uploadSuccess', res)
                  },
                  fail(err) {
                    _this.$emit('uploadFail', res)
                    console.error(err)
                  }
                })
              }
            },
            fail(err) {
              _this.$emit('drawFail', res)
              console.error(err)
            }
          }, _this)
        }, 1000)
      })
    },
    // 设置图像格式
    setImgInfo() {
      let _this = this
      const query = uni.createSelectorQuery().in(this)
      query.select('#m-v').boundingClientRect()
      query.exec(function (res) {
        let rect = res[0]
        _this.imgW = rect.width
        _this.imgH = rect.height

        _this.imgX = rect.left
        _this.imgY = rect.top
      })
    },
    // 移动层移动回调处理
    move(e) {
      this.setImgInfo()
    },
    // 移动层放大缩小回调处理
    handleScale(e) {
      this.scale = e.detail.scale
      this.setImgInfo()
    }
  }
}
</script>

<style scoped lang="scss">
view {
  box-sizing: border-box;
}

.flex {
  display: flex;
}

.flex.justify-between {
  justify-content: space-between;
}

.flex.justify-center {
  justify-content: center;
}

.flex.align-between {
  align-items: space-between;
}

.flex.align-center {
  align-items: center;
}

.cropper {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0);
  z-index: 99;

  .action {
    color: #fff;
    font-size: 32rpx;
    position: fixed;
    width: 100%;
    padding: 30rpx 30rpx 0 30rpx;
    z-index: 101;

    .close {
      width: 36rpx;
      height: 36rpx;
      vertical-align: middle;
      margin-right: 22rpx;
    }

    .success {
      width: 48rpx;
      height: 48rpx;
    }
  }

  .movable-area {
    position: fixed;
    width: 500%;
    height: 500%;
    overflow: hidden;
    z-index: 100;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);

    .m-view {
      width: 200rpx;
      height: 200rpx;
      box-sizing: border-box;
      display: flex;
      justify-content: center;
      align-items: center;
      background-color: transparent;
    }
  }

  .hole-bg {
    width: 100%;
    height: 100%;
    position: relative;
    z-index: 10;
    position: fixed;
    /*overflow: hidden;*/
    .hole {
      position: absolute;
      height: 560rpx;
      width: 560rpx;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
      content: '';
      border: 800rpx solid rgba(0, 0, 0, 0.5);
      box-sizing: content-box;

      &.hole.circle {
        border-radius: 50%;
      }
    }

    .square {
      position: absolute;
      height: 560rpx;
      width: 100%;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
      content: '';
      border: 800rpx solid rgba(0, 0, 0, 0.5);
      box-sizing: content-box;

      &.hole.circle {
        border-radius: 50%;
      }
    }
  }

  .img {
    position: fixed;
    z-index: 1;
    width: 200rpx;
    height: 200rpx;
  }

  .btn-group {
    position: fixed;
    bottom: 0;
    left: 0;
    z-index: 100;
    width: 100%;
    height: 100rpx;
    background-color: rgba(255, 255, 255, 0.5);

    .select-btn {
      font-size: 30rpx;
      background-color: rgba(255, 255, 255, 0.5);
      width: 50%;
      border-radius: 0;

      &:first-of-type {
        border-right: 1px solid #eee;
      }
    }
  }

  .download-img-container {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    z-index: 101;
    background-color: #fff;
    box-sizing: content-box;
    padding: 20rpx;

    .text {
      text-align: center;
    }

    image {
      width: 600rpx;
      height: 600rpx;
      border: 1px solid #000;
    }

    &.circle image {
      border-radius: 50%;
    }
  }
}


</style>
